<?php

namespace  App\Http\Controllers\AliPay;

use App\Http\Controllers\Controller;
use App\Rad_users;
use Illuminate\Http\Request;
use App\Common\AlipayConfig;
use App\Order;
use App\User;
use App\Coupon;
use App\Radcheck;
use App\Manage_user_list;

use App\Product;
use App\Radreply;

use  App\Http\Controllers\AliPay\AliPaySubmitController;


class AliPayNotifyController extends Controller
{
    var $config = null;

    public function __construct()
    {
        $this->config = new AlipayConfig();
    }

    /**
     * HTTPS形式消息验证地址
     */
    var $https_verify_url = 'https://mapi.alipay.com/gateway.do?service=notify_verify&';
    /**
     * HTTP形式消息验证地址
     */
    var $http_verify_url = 'http://notify.alipay.com/trade/notify_query.do?';

    /**
     * @param Request $request
     * 授权回调
     */
    public function PayCallback(Request $request)
    {
        $data = $request->all();

        $pay_channel = 1;

        self::fwrite($data);
        //  支付类型

        $verify_result = $this->verifyNotify($data);       //获取返回数据 验签

        self::fwrite($verify_result);
        $verify_result = true;
        if($verify_result){

            $trade_status = $data['trade_status'];             //交易状态

            if($trade_status == 'TRADE_FINISHED' || $trade_status == 'TRADE_SUCCESS') {             //订单处理

                $order = Order::where('order_no',$data['out_trade_no'])->first();

                $order->status = 1;
                $order->save();

                //  优惠号码标记已使用
                if($order->coupon_code)
                {
                    $coupon =  Coupon::where('coupon_code',$order->coupon_code)->first();
                    $coupon->is_use = 1;
                    $coupon->save();
                }
                $time = time();   //   当前时间

                //修改会员状态
                $user = Rad_users::find($order->to_user);
                
                $surplus_time  =  strtotime($user->expired_at);//  当前套餐到期时间
                if ($surplus_time<$time){
                	$surplus_time = $time;
                	$user->vip = 0;
                }
                
                //会员类型   不相相同   如果是高级会员转普通会员 直接转换后续时间，如果是普通会员转高级会员，普通会员清零后新开高级会员
                if ($user->vip==1 && $order->vip==2){
                	$surplus_time = $time;
                }
                $user->vip = $order->vip;

//                 if($user->vip == 0)
//                 {
//                 	switch($order->product_id)
//                 	{
//                 		case 1: $time = $time + 30*86400*$order->month;break;
//                 		case 2: $time = $time + 90*86400*$order->month;break;
//                 		case 3: $time = $time + 360*86400*$order->month;break;
//                 		case 4: $time = $time + 7*86400*$order->month;break;

//                 		case 9: $time = $time + 7*86400*$order->month;break;
//                 		case 6: $time = $time + 30*86400*$order->month;break;
//                 		case 7: $time = $time + 90*86400*$order->month;break;
//                 		case 8: $time = $time + 360*86400*$order->month;break;
//                 	}

//                 }else{
                	switch($order->product_id)
                	{
                	
                		case 1: $time = 30*86400*$order->month+$surplus_time;break;
                		case 2: $time = 90*86400*$order->month+$surplus_time;break;
                		case 3: $time = 360*86400*$order->month+$surplus_time;break;
                		case 4: $time = 7*86400*$order->month+$surplus_time;break;
                	
                		case 9: $time = 7*86400*$order->month+$surplus_time;break;
                		case 6: $time = 30*86400*$order->month+$surplus_time;break;
                		case 7: $time = 90*86400*$order->month+$surplus_time;break;
                		case 8: $time = 360*86400*$order->month+$surplus_time;break;
                	}

                $date = date('Y-m-d H:i:s',$time);
                $user->expired_at = $date;
//                $user->save();
//                Manage_user_list::where('username',$user->username)->update(['expired_at'=>$date]);

                //  radius  数据同步

                $time = date("d M Y H:i:s ",$time);
                Radcheck::where('username',$user->username)->where('attribute','=','Expiration')->update(['value'=>$time]);



                $order = Order::where('order_no',$data['out_trade_no'])->first();
                $product = Product::find($order->product_id);
                $speed = '';

                $set_meal_type = '';

                switch($product->type_id)
                {
                    case 1:$speed = '2048k/2048k';$set_meal_type = 2;break;
                    case 2:$speed = '4096k/4096k';$set_meal_type = 3;break;
                }
                $user->set_meal_type = $set_meal_type;
                $user->account_type = '付费';

                $user->save();

                $radreply = Radreply::where('username',$user->username)->where('attribute','Mikrotik-Rate-Limit')->first();
                $radreply->value = $speed;
                $radreply->save();




            }else {
                $error_msg = "ALIPAY_FAILED:支付宝支付失败 ";
                self::fwrite($error_msg);
            }

            echo "success";		//请不要修改或删除
        }else{
            echo "fail";        //验证失败
        }

        
    }


    /**
     * 针对notify_url验证消息是否是支付宝发出的合法消息
     * @return 验证结果
     */
    function verifyNotify($data){


        if(empty($data)) {//判断POST来的数组是否为空
            return false;
        }
        else {

            //生成签名结果
            $isSign = $this->getSignVeryfy($data, $data["sign"]);
            //获取支付宝远程服务器ATN结果（验证是否是支付宝发来的消息）
            $responseTxt = 'false';
            if (! empty($data["notify_id"])) {$responseTxt = $this->getResponse($data["notify_id"]);}

            //写日志记录
            //if ($isSign) {
            //	$isSignStr = 'true';
            //}
            //else {
            //	$isSignStr = 'false';
            //}
            //$log_text = "responseTxt=".$responseTxt."\n notify_url_log:isSign=".$isSignStr.",";
            //$log_text = $log_text.createLinkString($_POST);
            //logResult($log_text);

            //验证
            //$responsetTxt的结果不是true，与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
            //isSign的结果不是true，与安全校验码、请求时的参数格式（如：带自定义参数等）、编码格式有关
            if (preg_match("/true$/i",$responseTxt) && $isSign) {
                return true;
            } else {
                return false;
            }
        }
    }




    static function fwrite($data){
//        date_default_timezone_set('PRC');
//        $timestamp = time();
//        $current_date = strftime('%Y-%m', $timestamp);
//        // 首先需要检测b目录是否存在
//        $file=storage_path('logs/'.$current_date);
//        if(!file_exists($file)) mkdir($file,0777);
//        $current_time = strftime('%Y-%m-%d', $timestamp);
//        $file =$file."/$current_time.pay_log.txt";
//        $myFile = fopen($file, "a+") or die("Unable to open file!");
//        $txt = self::getCurrentTime()."   ".$data."\n";
//        fwrite($myFile, $txt);
//        fclose($myFile);
    }


    /**
     * 针对return_url验证消息是否是支付宝发出的合法消息
     * @return 验证结果
     */
    function verifyReturn(){
        if(empty($_GET)) {//判断POST来的数组是否为空
            return false;
        }
        else {
            //生成签名结果
            $isSign = $this->getSignVeryfy($_GET, $_GET["sign"]);


            //获取支付宝远程服务器ATN结果（验证是否是支付宝发来的消息）
            $responseTxt = 'false';
            if (! empty($_GET["notify_id"])) {$responseTxt = $this->getResponse($_GET["notify_id"]);}

            //写日志记录
            //if ($isSign) {
            //	$isSignStr = 'true';
            //}
            //else {
            //	$isSignStr = 'false';
            //}
            //$log_text = "responseTxt=".$responseTxt."\n return_url_log:isSign=".$isSignStr.",";
            //$log_text = $log_text.createLinkString($_GET);
            //logResult($log_text);

            //验证
            //$responsetTxt的结果不是true，与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
            //isSign的结果不是true，与安全校验码、请求时的参数格式（如：带自定义参数等）、编码格式有关

            if (preg_match("/true$/i",$responseTxt) && $isSign) {
                return true;
            } else {
                return false;
            }
        }
    }

    /**
     * 获取返回时的签名验证结果
     * @param $para_temp 通知返回来的参数数组
     * @param $sign 返回的签名结果
     * @return 签名验证结果
     */
    function getSignVeryfy($para_temp, $sign) {


        $alipay_config = [];
        $alipay_config['sign_type'] = $this->config->sign_type;     //  签名方式
        $alipay_config['input_charset'] = 'utf-8';     //字符集
        $alipay_config['partner'] = $this->config->partner;             //合作身份者ID;

        $submit = new AliPaySubmitController($alipay_config);

        //除去待签名参数数组中的空值和签名参数
        $para_filter = $submit->paraFilter($para_temp);

        //对待签名参数数组排序
        $para_sort = $submit->argSort($para_filter);

        //把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
        $prestr = $submit->createLinkstring($para_sort);

        $isSgin = false;
        switch (strtoupper(trim($this->config->sign_type))) {
            case "RSA" :
                $alipay_public_key_path = app()->basePath('app')."/Common/alipay_public_key.pem";

                $alipay_public_key = file_get_contents($alipay_public_key_path);
                $isSgin = $this->rsaVerify($prestr, trim($alipay_public_key), $sign);
                break;
            default :
                $isSgin = false;
        }

        return $isSgin;
    }


    /**
     * RSA验签
     * @param $data 待签名数据
     * @param $alipay_public_key 支付宝的公钥字符串
     * @param $sign 要校对的的签名结果
     * return 验证结果
     */
    function rsaVerify($data, $alipay_public_key, $sign)  {
        //以下为了初始化私钥，保证在您填写私钥时不管是带格式还是不带格式都可以通过验证。
        $alipay_public_key=str_replace("-----BEGIN PUBLIC KEY-----","",$alipay_public_key);
        $alipay_public_key=str_replace("-----END PUBLIC KEY-----","",$alipay_public_key);
        $alipay_public_key=str_replace("\n","",$alipay_public_key);
        $alipay_public_key='-----BEGIN PUBLIC KEY-----'.PHP_EOL.wordwrap($alipay_public_key, 64, "\n", true) .PHP_EOL.'-----END PUBLIC KEY-----';

        $res=openssl_get_publickey($alipay_public_key);

        if($res)
        {
            $result = (bool)openssl_verify($data, base64_decode($sign), $res);
        }
        else {
            self::fwrite("您的支付宝公钥格式不正确!"."<br/>"."The format of your alipay_public_key is incorrect!");
            echo "您的支付宝公钥格式不正确!"."<br/>"."The format of your alipay_public_key is incorrect!";
            exit();
        }
        openssl_free_key($res);

        return $result;
    }


    /**
     * 获取远程服务器ATN结果,验证返回URL
     * @param $notify_id 通知校验ID
     * @return 服务器ATN结果
     * 验证结果集：
     * invalid命令参数不对 出现这个错误，请检测返回处理中partner和key是否为空
     * true 返回正确信息
     * false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟
     */
    function getResponse($notify_id) {
        $transport = strtolower(trim($this->config->transport));
        $partner = trim($this->config->partner);
        $veryfy_url = '';
        if($transport == 'https') {
            $veryfy_url = $this->https_verify_url;
        }
        else {
            $veryfy_url = $this->http_verify_url;
        }
        $veryfy_url = $veryfy_url."partner=" . $partner . "&notify_id=" . $notify_id;

        $cacert_path = app()->basePath('app')."/Common/cacert.pem";     //   证书地址
        $responseTxt = $this->getHttpResponseGET($veryfy_url, $cacert_path);

        return $responseTxt;
    }



    /**
     * 远程获取数据，GET模式
     * 注意：
     * 1.使用Crul需要修改服务器中php.ini文件的设置，找到php_curl.dll去掉前面的";"就行了
     * 2.文件夹中cacert.pem是SSL证书请保证其路径有效，目前默认路径是：getcwd().'\\cacert.pem'
     * @param $url 指定URL完整路径地址
     * @param $cacert_url 指定当前工作目录绝对路径
     * return 远程输出的数据
     */
    function getHttpResponseGET($url,$cacert_url) {
        $curl = curl_init($url);
        curl_setopt($curl, CURLOPT_HEADER, 0 ); // 过滤HTTP头
        curl_setopt($curl,CURLOPT_RETURNTRANSFER, 1);// 显示输出结果
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);//SSL证书认证
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);//严格认证
        curl_setopt($curl, CURLOPT_CAINFO,$cacert_url);//证书地址
        $responseText = curl_exec($curl);
        //var_dump( curl_error($curl) );//如果执行curl过程中出现异常，可打开此开关，以便查看异常内容
        curl_close($curl);

        return $responseText;
    }

}
